package org.gpp.proj1.bone.parser;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.gpp.proj1.bone.Bone;
import org.gpp.proj1.bone.BoneStructure;
import org.gpp.proj1.bone.InvalidKeyframeFileException;
/**
 * Classe que l� um arquivo de configura��o de estruturas e 
 * gera uma esturtura a partir do mesmo
 * @author Pablo Diego
 */
public class BoneStructureParser {

	private String file;
	
	/**
	 * Cria um parser de Estruturas a partir
	 * @param aquivo
	 */
	public BoneStructureParser(String file){
		
		this.file = file;
	}
	
	/**
	 * Obt�m uma estrutura a partir de um arquivo
	 * @return BoneStructure que estava no arquivo
	 * @throws BoneStructureParserException
	 */
	public BoneStructure getBoneStructure() throws BoneStructureParserException{
		
		Bone rootBone = null;
		String animationFile = null;
		Map<String, Bone> bones = new HashMap<String, Bone>();
		Map<String, Map<String, Bone>> boneGroups = new HashMap<String, Map<String, Bone>>(); 

		try{
			
			BufferedReader reader = new BufferedReader(new FileReader(this.file));
			
			String linha = null;
			int contLinhas = 1;
			
			try {
				
				while( (linha = reader.readLine()) != null ){
					if( linha.trim().equals("") ) {
						continue;
					}
					
					String[] tokens = linha.split(" ");
					
					String lineStart = tokens[0];
					
					if( lineStart.equals("defineRootBone") ){
						
						if( rootBone == null ){
							
							String rootBoneName = tokens[1];
							rootBone = animationFile != null ? new Bone( rootBoneName, animationFile ) : new Bone( rootBoneName );
							bones.put(rootBoneName, rootBone);
						}
						else{
							
							throw new BoneStructureParserException("Dupla defini��o de raiz na linha " + contLinhas);
						}
					} else if( lineStart.equals("defineAnimationFile") ){
						if( tokens.length == 2 ) {
							animationFile = tokens[1];
						} else {
							throw new BoneStructureParserException( "Invalid line, ignoring: " + linha );							
						}
					} else if( lineStart.equals("defineBoneGroup") ){
						String boneGroup = tokens[1];
						
						if( ! boneGroups.containsKey( boneGroup ) ) {
							boneGroups.put( boneGroup, new HashMap<String, Bone>() );	
						}
						
						for( int k = 2; k < tokens.length; k++ ) {
							String groupElement = tokens[k];
							
							if( ! bones.containsKey( groupElement ) ) {
								
								throw new BoneStructureParserException( "Error: group element isn't defined. At line " + contLinhas );
							}
							
							boneGroups.get( boneGroup ).put( groupElement, bones.get( groupElement ) );
						}
					} else { // Parent -> child definition
						
						String childBoneName = tokens[0];
						String keyword = tokens[1];
						String boneName = tokens[2];
						
						if( !keyword.equals("connectsTo") ){
							
							throw new BoneStructureParserException("Erro de sintaxe na linha " + contLinhas);
						}
						
						//caso o hash n�o tenha ainda esse bone o adicione
						if(!bones.containsKey(childBoneName)){
							
							Bone newBone = animationFile != null ? new Bone( childBoneName, animationFile ) : new Bone( childBoneName );
							
							bones.put(newBone.getName(), newBone);
						}
						
						if( !bones.containsKey(childBoneName) ){

							throw new BoneStructureParserException("O bone a ser conectado n�o existe! " + contLinhas );
						}
						else{

							//adiciona um filho
							bones.get( boneName ).attachChild( bones.get(childBoneName) );
						}
					}
					
					contLinhas++;
				}
				
				reader.close();
			} catch (IOException e) {
				throw new BoneStructureParserException( "Could not read file", e );
			} catch (InvalidKeyframeFileException e) {
				throw new BoneStructureParserException( "Invalid animation keyframe file", e );
			}
		
		}catch(FileNotFoundException ex){
			
			throw new BoneStructureParserException("Arquivo passado n�o encontrado!");
		}
				
		return new BoneStructure(rootBone, bones, boneGroups);
	}
	
	public String getFile() {
		return this.file;
	}

	public void setFile(String file) {
		this.file = file;
	}
}
